/* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <dlfcn.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "platform.h"
#include "sml_errcodes.h"
#include "sml.h"
#include "sml_common.h"

// include LSI storelib header files start
#include "lsi/storelib.h"
#include "mfi.h"

#include "sl_diagnose.h"
#include "sl.h"
#include "sl_misc.h"
#include "sl_ctrl.h"

/* 解决包含mpi2.h、mpi2_cnfg.h的编译问题 */
#define MPI2_POINTER *

#include "lsi/mpi2.h"
#include "lsi/mpi2_cnfg.h"
// include LSI storelib header files end

#include <errno.h>

// refer to LSI storelib_test tool's implementation
static gint32 GetCtrlHealth(guint32 ctrl_id, SL_CTRL_HEALTH_T *pCtrlHealth);
static gint32 GetConfigPageInfo(guint32 ctrl_id, guint8 phyIdentifier, MPI2_CONFIG_PAGE_SAS_PHY_1 *pSasPhy1);
static gint32 GetCtrlPhyConnectionsInfo(guint32 ctrl_id, MR_SAS_PHY_CONNECTIONS *pPhyConnections);
static gint32 GetCtrlBBUStatus(guint32 ctrl_id, MR_BBU_STATUS *pBBUStatus);
static gint32 GetCtrlLDList(guint32 ctrl_id, MR_LD_LIST *pLdList);
static gint32 GetCtrlPDList(guint32 ctrl_id, MR_PD_LIST *pPdList, guint32 dataSize);
static gint32 SetCtrlPropCmd(guint32 ctrl_id, MR_CTRL_PROP *pProp);
static gint32 GetCtrlPropCmd(guint32 ctrl_id, MR_CTRL_PROP *pProp);
static gint32 SetCtrlFactoryDefaultscmd(guint32 ctrl_id);
static gint32 SetCtrlDisableCopyBack(guint32 ctrl_id, guint8 disable);
static gint32 SetCtrlEnableSmartCopyBack(guint32 ctrl_id, guint8 enable);
static gint32 SetCtrlEnableJbod(guint32 ctrl_id, guint8 enable);
static gint32 SetCtrlRestoreDefault(guint32 ctrl_id);
static gint32 ConvertDirectAttachedPdEid(MR_PD_LIST *pPdList, guint16 *pCovertedEid);
static gint32 GetExpanderPhyErrorLog(guint32 ctrl_id, SML_CTRL_EXP_SASPHY_INFO_S *expander);
static void BuildSasAddrList(const void *data, guint32 data_size, SL_LIST_ELEMENT_T *sas_addr_list,
    gint32 *sas_addr_count);
static void BuildSasListExp(const void *start_data, guint32 data_size, U16 device_offset,
    SL_LIST_ELEMENT_T *sas_addr_list, gint32 *sas_addr_count);
static gint32 GetCtrlMode(guint32 ctrl_id, guint8 *ctrl_personality_mode, SML_CTRL_OPERATIONS_S* ctrl_operations);
static gint32 FireSMPPassthruCmd(guint32 ctrl_id, SL_SMP_PASSTHRU_T *smp_passthru_cmd);

/*
 * Description: 更新storelib中的缓存数据
 * History: 2017年6月1日  新生成函数
*/
static void UpdateCtrlCacheInStorelib(guint32 ctrl_id)
{
    gint32 retval = SL_SUCCESS;
    SL_LIB_CMD_PARAM_T libCmdParam;
    guint8 libType = 0;

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_UPDATE_CONTROLLER_CACHE;
    libCmdParam.ctrlId = ctrl_id;

    if (SL_SUCCESS != (retval = ProcessLibCommandCall(libType, &libCmdParam))) {
        debug_log(DLOG_DEBUG, "Update storelib cache failed, return 0x%04X", retval);
    }

    return;
}

/*
 * Description: 发送命令给storelib获取LSI RAID控制器的健康数据
 * History: 2016年3月7日  新生成函数
*/
static gint32 GetCtrlHealth(guint32 ctrl_id, SL_CTRL_HEALTH_T *pCtrlHealth)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pCtrlHealth) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_CTRL_HEALTH;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)SL_CTRL_HEALTH_S;
    libCmdParam.pData = pCtrlHealth;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 发送命令给storelib获取SAS Config Page信息
 * History: 2016年3月8日  新生成函数
*/
static gint32 GetConfigPageInfo(guint32 ctrl_id, guint8 phyIdentifier, MPI2_CONFIG_PAGE_SAS_PHY_1 *pSasPhy1)
{
    gint32 retval;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;
    size_t dataLen = sizeof(MR_SAS_CONFIG_PAGE) - sizeof(guint8) + sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1);

    if (NULL == pSasPhy1) {
        return SML_ERR_NULL_DATA;
    }

    MR_SAS_CONFIG_PAGE *pSasCfgPage = (MR_SAS_CONFIG_PAGE *)g_malloc(dataLen);

    if (NULL == pSasCfgPage) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    (void)memset_s(pSasCfgPage, dataLen, 0, dataLen);
    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    pSasCfgPage->action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
    pSasCfgPage->extPageLength = (guint16)sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1);
    pSasCfgPage->pageNumber = 1;
    pSasCfgPage->extPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
    pSasCfgPage->pageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
    pSasCfgPage->pageAddress = phyIdentifier;
    pSasCfgPage->mpiGenVersion = 1;

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_SAS_CONFIG_PAGE_PASSTHROUGH;

    if (SL_LIB_TYPE_STORELIBIT == libType || SL_LIB_TYPE_STORELIBIR_3 == libType ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        dcmdInput.flags = SL_DIR_READ;
    } else {
        dcmdInput.flags = SL_DIR_BOTH;
    }

    dcmdInput.dataTransferLength = dataLen;
    dcmdInput.pData = pSasCfgPage;

    if (SML_SUCCESS == (retval = ProcessLibCommandCall(libType, &libCmdParam))) {
        if (pSasCfgPage->pageType != MPI2_CONFIG_PAGETYPE_EXTENDED || pSasCfgPage->pageAddress != phyIdentifier) {
            debug_log(DLOG_ERROR, "PageType or PageAddress doesn't match");
            retval = SML_ERR_DATA_INVALID;
        } else {
            (void)memcpy_s(pSasPhy1, sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1), pSasCfgPage->pageBuffer,
                sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1));
        }
    }

    g_free(pSasCfgPage);

    return retval;
}

/*
 * Description: 发送命令给storelib获取LSI RAID控制器的PHY连接状态
 * History: 2016年3月7日  新生成函数
*/
static gint32 GetCtrlPhyConnectionsInfo(guint32 ctrl_id, MR_SAS_PHY_CONNECTIONS *pPhyConnections)
{
    gint32 ret;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;

    if (NULL == pPhyConnections) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    dcmdInput.opCode = MR_DCMD_SAS_CONFIG_GET_PHY_CONNECTIONS;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.dataTransferLength = (guint32)sizeof(MR_SAS_PHY_CONNECTIONS);
    dcmdInput.pData = pPhyConnections;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && pPhyConnections->count > SML_MAX_SAS_PHY_PER_CTRL) {
        debug_log(DLOG_DEBUG,
            "smlib: LSI:GetCtrlPhyConnectionsInfo failed, CtrlId = %d, returned count = %u, count is larger than %d",
            SML_CTRL_ID_VALID_BIT(ctrl_id), pPhyConnections->count, SML_MAX_SAS_PHY_PER_CTRL);
        return SML_ERR_DATA_INVALID;
    }
    return ret;
}

/*
 * Description: 发送命令给storelib获取LSI RAID卡的BBU状态
 * History: 2016年3月7日  新生成函数
*/
static gint32 GetCtrlBBUStatus(guint32 ctrl_id, MR_BBU_STATUS *pBBUStatus)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pBBUStatus) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_BBU_CMD_TYPE;
    libCmdParam.cmd = SL_GET_BBU_STATUS;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)sizeof(MR_BBU_STATUS);
    libCmdParam.pData = pBBUStatus;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 获取BBU的标称信息
 * History: 2016年4月1日  新生成函数
*/
static gint32 GetCtrlBBUDegsinInfo(guint32 ctrl_id, MR_BBU_DESIGN_INFO *pbbuDesign)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pbbuDesign) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_BBU_CMD_TYPE;
    libCmdParam.cmd = SL_GET_BBU_DESIGN_INFO;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)sizeof(MR_BBU_DESIGN_INFO);
    libCmdParam.pData = pbbuDesign;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 发送命令给storelib获取LSI RAID卡的LD概况
 * History: 2016年3月7日  新生成函数
*/
static gint32 GetCtrlLDList(guint32 ctrl_id, MR_LD_LIST *pLdList)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

    if (NULL == pLdList) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_LD_LIST;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)sizeof(MR_LD_LIST);
    libCmdParam.pData = pLdList;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && pLdList->ldCount > SML_MAX_LOGIC_DRIVES) {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlLDList failed, CtrlId = %d, returned count = %u, larger than %d",
            SML_CTRL_ID_VALID_BIT(ctrl_id), pLdList->ldCount, SML_MAX_LOGIC_DRIVES);
        return SML_ERR_DATA_INVALID;
    }
    return ret;
}

/*
 * Description: 发送命令给storelib获取LSI RAID卡的PD概况
 * History: 2016年3月7日  新生成函数
*/
static gint32 GetCtrlPDList(guint32 ctrl_id, MR_PD_LIST *pPdList, guint32 dataSize)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    gint32 ret;

    if (NULL == pPdList) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_PD_LIST;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = dataSize;
    libCmdParam.pData = pPdList;

    ret = ProcessLibCommandCall(libType, &libCmdParam);
    if (ret == SML_SUCCESS && pPdList->count > SML_MAX_PHYSICAL_DRIVES) {
        debug_log(DLOG_DEBUG,
            "smlib: LSI:GetCtrlPDList failed, CtrlId = %d, returned count = %u, count is larger than %d",
            SML_CTRL_ID_VALID_BIT(ctrl_id), pPdList->count, SML_MAX_PHYSICAL_DRIVES);
        return SML_ERR_DATA_INVALID;
    }
    return ret;
}

/*
 * Description: 发送SMP Passthru命令
 * History: 2018年10月31日  新生成函数 AR.SR.SFEA02130924.009.011
*/
static gint32 FireSMPPassthruCmd(guint32 ctrl_id, SL_SMP_PASSTHRU_T *smp_passthru_cmd)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (smp_passthru_cmd == NULL) {
        return SML_ERR_NULL_DATA;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    (void)memset_s(&libCmdParam, sizeof(SL_LIB_CMD_PARAM_T), 0, sizeof(SL_LIB_CMD_PARAM_T));

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_SMP_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.pData = smp_passthru_cmd;
    libCmdParam.dataSize = (guint32)SL_SMP_PASSTHRU_S;

    retval = ProcessLibCommandCall(libType, &libCmdParam);

    return retval;
}

/*
 * Description: 获取Expander的某个PHY Error Log
 */
static gint32 GetExpSinglePhyErrCount(guint32 ctrl_id, guint32 phy_id, guint64 sas_addr,
    SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T *smp_response)
{
    SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_T *smp_request = NULL;
    SL_SMP_PASSTHRU_T *smp_passthru = NULL;
    guint8 *request_buff = NULL;
    size_t smp_passthru_length;
    gint32 ret;

    smp_request = (SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_T *)g_malloc0(SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);
    if (smp_request == NULL) {
        debug_log(DLOG_DEBUG, "%s allocate memory fail", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    smp_passthru_length =
        SL_SMP_PASSTHRU_S + SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S + SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
    smp_passthru = (SL_SMP_PASSTHRU_T *)g_malloc0(smp_passthru_length);
    if (smp_passthru == NULL) {
        debug_log(DLOG_DEBUG, "%s allocate memory fail", __FUNCTION__);
        g_free(smp_request);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    (void)memset_s(smp_request, SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S, 0, SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);
    (void)memset_s(smp_passthru, smp_passthru_length, 0, smp_passthru_length);

    smp_passthru->sasAddr = sas_addr;
    smp_passthru->dir = SL_DIR_BOTH;
    smp_passthru->requestLen = (guint32)SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S;
    smp_passthru->responseLen = SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
    smp_request->phyID = phy_id;
    smp_request->function = SL_SMP_FUNCTION_CODE_REPORT_PHY_ERROR_LOG;
    smp_request->smpFrameType = SL_SMP_REQUEST_FRAME_TYPE;

    /* 绕过数组越界的编译告警 */
    request_buff = smp_passthru->responseBuffer;
    request_buff = request_buff + SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
    (void)memcpy_s(request_buff, SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S, smp_request,
        SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);

    ret = FireSMPPassthruCmd(ctrl_id, smp_passthru);
    if (ret != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "Get RAID expander phy err log failed, ctrl_id=%d, ret=%d", ctrl_id, ret);
        g_free(smp_request);
        g_free(smp_passthru);
        return ret;
    }

    (void)memcpy_s(smp_response, sizeof(SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T), smp_passthru->responseBuffer,
        sizeof(SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T));
    if (smp_response->functionResult != 0) {
        debug_log(DLOG_DEBUG, "Get RAID expander phy err log failed, ctrl_id=%d, func_ret=%d", ctrl_id,
            smp_response->functionResult);
    }

    g_free(smp_request);
    g_free(smp_passthru);
    return ret;
}

/*
 * Description: 获取Expander的PHY Error Log
 * History: 2018年10月31日  新生成函数 AR.SR.SFEA02130924.009.011
*/
static gint32 GetExpanderPhyErrorLog(guint32 ctrl_id, SML_CTRL_EXP_SASPHY_INFO_S *expander)
{
    gint32 rval = SML_SUCCESS;  // 获取拓扑的返回值
    gint32 rval2 = SML_SUCCESS; // 获取单个PHY误码的返回值
    SL_SMP_PASSTHRU_T *smp_passthru = NULL;
    SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_T *smp_request = NULL;
    SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T *smp_response = NULL;
    SL_LIST_ELEMENT_T sas_addr_list[MAX_PHYSICAL_DEVICES];
    void *topology_buffer = NULL;
    gint32 exp_sas_addr_count = 0;
    size_t smp_passthru_length;
    gint32 i, j;
    guint32 tmp = 0;

    if (NULL == expander) {
        return SML_ERR_NULL_DATA;
    }
    memset_s(sas_addr_list, sizeof(sas_addr_list), 0, sizeof(sas_addr_list));

    topology_buffer = g_malloc0(SL_TOPOLOGY_BUFFER_SIZE);
    if (topology_buffer == NULL) {
        debug_log(DLOG_DEBUG, "Get Expander PHY error log allocate topology_buffer memory failure");
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    /* 获取拓扑信息 */
    rval = GetTopologyInfo(ctrl_id, SL_TOPOLOGY_BUFFER_SIZE, topology_buffer);
    if (SL_SUCCESS != rval) {
        debug_log(DLOG_DEBUG, "GetTopologyInfo fail, ctrl_id=%d, rval=%d", ctrl_id, rval);
        g_free(topology_buffer);
        return rval;
    }

    /* 从拓扑中得到Expander的SAS地址列表 */
    BuildSasAddrList(topology_buffer, SL_TOPOLOGY_BUFFER_SIZE, sas_addr_list, &exp_sas_addr_count);

    /* 拓扑数据用完，释放掉 */
    g_free(topology_buffer);

    /* 判断Expander数量是否为0 */
    if (0 == exp_sas_addr_count) {
        debug_log(DLOG_DEBUG, "Get RAID Expander SAS Addr Count is 0, ctrl_id=%d", ctrl_id);
        return SML_ERR_EXP_NO_EXPANDER;
    }

    /* 判断Expander数量是否超过了限制 */
    if (exp_sas_addr_count > SML_MAX_EXPANDER_PER_CONTROLLER) {
        debug_log(DLOG_DEBUG, "Get RAID Expander Num %d greater than %d, ctrl_id=%d", exp_sas_addr_count,
            SML_MAX_EXPANDER_PER_CONTROLLER, ctrl_id);
        exp_sas_addr_count = SML_MAX_EXPANDER_PER_CONTROLLER;
    }

    smp_request = (SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_T *)g_malloc0(SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);
    if (NULL == smp_request) {
        debug_log(DLOG_DEBUG, "Get Expander PHY error log allocate smp_phy_request memory failure");
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    smp_passthru_length =
        SL_SMP_PASSTHRU_S + SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S + SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
    smp_passthru = (SL_SMP_PASSTHRU_T *)g_malloc0(smp_passthru_length);
    if (NULL == smp_passthru) {
        debug_log(DLOG_DEBUG, "Get Expander PHY error log allocate smp_passthru memory failure");
        g_free(smp_request);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    expander->expander_count = exp_sas_addr_count;

    /* 遍历Expander背板 */
    for (i = 0; i < exp_sas_addr_count; i++) {
        if (sas_addr_list[i].deviceType != SL_END_DEVICE) {
            /* 如果获取的Expander的phy数量为0，说明RAID卡的fw可能为老版本的 */
            if (0 == sas_addr_list[i].numPhy) {
                rval = SML_ERR_EXP_NO_PHY;
                break;
            }

            /* 排除Expander的虚拟phy，不获取误码信息 */
            expander->expander_phy[i].phy_count = sas_addr_list[i].numPhy - sas_addr_list[i].numVirtualPhy;

            /* 判断phy数量是否超过了限制 */
            if (expander->expander_phy[i].phy_count > SML_MAX_SAS_PHY_PER_EXPANDER) {
                debug_log(DLOG_DEBUG, "Get RAID Expander Phy Num %d greater than %d, ctrl_id=%d, expander_id=%d",
                    expander->expander_phy[i].phy_count, SML_MAX_SAS_PHY_PER_EXPANDER, ctrl_id, i);
                expander->expander_phy[i].phy_count = SML_MAX_SAS_PHY_PER_EXPANDER;
            }

            /* 遍历phy，发送SMP Passthru命令 */
            for (j = 0; j < expander->expander_phy[i].phy_count; j++) {
                smp_passthru->sasAddr = sas_addr_list[i].sasAddr;
                smp_passthru->dir = SL_DIR_BOTH;
                smp_passthru->requestLen = (guint32)SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S;
                smp_passthru->responseLen = SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
                smp_request->phyID = j;
                smp_request->function = SL_SMP_FUNCTION_CODE_REPORT_PHY_ERROR_LOG;
                smp_request->smpFrameType = SL_SMP_REQUEST_FRAME_TYPE;

                /* 绕过数组越界的编译告警 */
                guint8 *request_buff = smp_passthru->responseBuffer;
                request_buff = request_buff + SL_SMP_MAX_RESPONSE_BUFFER_LEN_SAS_1;
                memcpy_s(request_buff, SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S, smp_request,
                    SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);

                rval2 = FireSMPPassthruCmd(ctrl_id, smp_passthru);
                if (SML_SUCCESS == rval2) {
                    smp_response = (SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T *)smp_passthru->responseBuffer;
                    if (0 == smp_response->functionResult) {
                        /* 获取的phy误码数据需要转换大小端 */
                        swapBytes((void *)&smp_response->invalidDwordCount, (void *)&tmp,
                            sizeof(smp_response->invalidDwordCount));
                        expander->expander_phy[i].phy_err[j].invalid_dword_count = tmp;
                        swapBytes((void *)&smp_response->runningDisparityErrorCount, (void *)&tmp,
                            sizeof(smp_response->runningDisparityErrorCount));
                        expander->expander_phy[i].phy_err[j].running_disparity_error_count = tmp;
                        swapBytes((void *)&smp_response->lossDwordSyncCount, (void *)&tmp,
                            sizeof(smp_response->lossDwordSyncCount));
                        expander->expander_phy[i].phy_err[j].loss_dword_sync_count = tmp;
                        swapBytes((void *)&smp_response->phyResetProblemCount, (void *)&tmp,
                            sizeof(smp_response->phyResetProblemCount));
                        expander->expander_phy[i].phy_err[j].phy_reset_problem_count = tmp;
                    } else {
                        debug_log(DLOG_DEBUG,
                            "Get RAID expander phy err log failed, ctrl_id=%d, expander_id=%d, phy_id=%d, func_ret=%d",
                            ctrl_id, i, j, smp_response->functionResult);
                    }
                } else {
                    debug_log(DLOG_DEBUG,
                        "Get RAID expander phy err log failed, ctrl_id=%d, expander_id=%d, phy_id=%d, ret=%d", ctrl_id,
                        i, j, rval2);
                }

                (void)memset_s(smp_request, SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S, 0,
                    SL_SMP_REQUEST_REPORT_PHY_ERROR_LOG_S);
                (void)memset_s(smp_passthru, smp_passthru_length, 0, smp_passthru_length);
                vos_task_delay(100);
            }
        }
    }

    g_free(smp_request);
    g_free(smp_passthru);

    return rval;
}

/*
 * Description: 得到Expander的Sas地址列表
 * History: 2018年10月31日  新生成函数 AR.SR.SFEA02130924.009.011
*/
static void BuildSasAddrList(const void *data, guint32 data_size, SL_LIST_ELEMENT_T *sas_addr_list,
    gint32 *sas_addr_count)
{
    gint32 i;
    SL_TOPOLOGY_HEAD_PHY_T *headPhy = NULL;
    SL_TOPOLOGY_HEAD_NODE_T *head = NULL;

    if (data == NULL) {
        return;
    }
    if (sas_addr_list == NULL) {
        return;
    }
    if (sas_addr_count == NULL) {
        return;
    }

    if (data_size < sizeof(SL_TOPOLOGY_HEAD_NODE_T)) {
        return;
    }

    head = (SL_TOPOLOGY_HEAD_NODE_T *)data;
    headPhy = head->phyList;

    for (i = 0; i < head->numPhy; i++) {
        if (headPhy->attachedDeviceType == SL_EDGE_EXPANDER || headPhy->attachedDeviceType == SL_FANOUT_EXPANDER) {
            BuildSasListExp(data, data_size, headPhy->attachedDeviceOffset, sas_addr_list, sas_addr_count);
        }

        headPhy++;
    }
}

/*
 * Description: 迭代得到Expander的Sas地址列表
 * History: 2018年10月31日  新生成函数 AR.SR.SFEA02130924.009.011
*/
static void BuildSasListExp(const void *start_data, guint32 data_size, U16 device_offset,
    SL_LIST_ELEMENT_T *sas_addr_list, gint32 *sas_addr_count)
{
    SL_TOPOLOGY_EXPANDER_NODE_T *topoEx = NULL;
    SL_TOPOLOGY_END_DEVICE_NODE_T *endNode = NULL;
    gint32 i, j;

    if (start_data == NULL) {
        return;
    }
    if (sas_addr_list == NULL) {
        return;
    }

    if ((sizeof(SL_TOPOLOGY_EXPANDER_NODE_T) + device_offset) > data_size) {
        return;
    }
    topoEx = (SL_TOPOLOGY_EXPANDER_NODE_T *)((U8 *)start_data + device_offset);

    /* 递归最大数量限制 */
    if (MAX_PHYSICAL_DEVICES <= *sas_addr_count) {
        debug_log(DLOG_ERROR, "Get Expander SAS addr count from topology greater than %d", MAX_PHYSICAL_DEVICES);
        return;
    }
    /* 跳过已遍历在列表中的sas_addr */
    for (i = 0; i < *sas_addr_count; i++) {
        if (sas_addr_list[i].sasAddr == topoEx->sasAddr) {
            break;
        }
    }

    /* 不是已遍历过的sas_addr，说明为新的Expander，记录在列表中 */
    if (i != *sas_addr_count) {
        return;
    }

    j = *sas_addr_count;
    sas_addr_list[*sas_addr_count].sasAddr = topoEx->sasAddr;
    sas_addr_list[*sas_addr_count].numPhy = topoEx->numPhy;
    sas_addr_list[*sas_addr_count].deviceType = topoEx->deviceType;
    sas_addr_list[*sas_addr_count].devBitMap.deviceWord = topoEx->deviceBitMap.deviceWord;
    *sas_addr_count = (*sas_addr_count) + 1;
    /* 遍历Expander的所有phy */
    for (i = 0; i < topoEx->numPhy; i++) {
        /* 如果为phy的下挂设备类型为Expander，则进入递归的下一层 */
        if (topoEx->phyList[i].attachedDeviceType == SL_EDGE_EXPANDER ||
            topoEx->phyList[i].attachedDeviceType == SL_FANOUT_EXPANDER) {
            if (device_offset != topoEx->phyList[i].attachedDeviceOffset) {
                BuildSasListExp(start_data, data_size, topoEx->phyList[i].attachedDeviceOffset, &sas_addr_list[0],
                    sas_addr_count);
            }
        } else if (topoEx->phyList[i].attachedDeviceType == SL_END_DEVICE) {
            if ((sizeof(SL_TOPOLOGY_END_DEVICE_NODE_T) + topoEx->phyList[i].attachedDeviceOffset) > data_size) {
                continue;
            }
            endNode = (SL_TOPOLOGY_END_DEVICE_NODE_T *)((U8 *)start_data + topoEx->phyList[i].attachedDeviceOffset);
            /* 如果phy连接的endDevice的deviceBitMap类型同时有Initiator和Target，则该phy为虚拟phy */
            if (CheckPHYIsVirtual(endNode) == TRUE) {
                sas_addr_list[j].numVirtualPhy++;
            }
        }
    }
}

/*
 * Description: 向控制器发送设置属性值的命令
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlPropCmd(guint32 ctrl_id, MR_CTRL_PROP *pProp)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pProp) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_SET_CTRL_PROPERTIES;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)sizeof(MR_CTRL_PROP);
    libCmdParam.pData = pProp;

    memcpy_s(&libCmdParam.genRef.ref_2b[0], sizeof(guint16), &pProp->seqNum, sizeof(guint16));

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 向控制器发送获取属性值的命令
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 GetCtrlPropCmd(guint32 ctrl_id, MR_CTRL_PROP *pProp)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;

    if (NULL == pProp) {
        return SML_ERR_NULL_DATA;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(pProp, sizeof(MR_CTRL_PROP), 0, sizeof(MR_CTRL_PROP));

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CTRL_CMD_TYPE;
    libCmdParam.cmd = SL_GET_CTRL_PROPERTIES;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)sizeof(MR_CTRL_PROP);
    libCmdParam.pData = pProp;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 向控制器发送设置属性值的命令
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlFactoryDefaultscmd(guint32 ctrl_id)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    dcmdInput.opCode = MR_DCMD_CTRL_SET_FACTORY_DEFAULTS;
    dcmdInput.flags = SL_DIR_NONE;

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 设置是否禁止指定控制器的CopyBack功能
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlDisableCopyBack(guint32 ctrl_id, guint8 disable)
{
    gint32 retval = SML_SUCCESS;
    MR_CTRL_PROP prop;
    guint8 on_off = 0;

    // 获取所有属性值，不修改的属性直接按原先的值写回
    retval = GetCtrlPropCmd(ctrl_id, &prop);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib LSI: SetCtrlDisableCopyBack -> Get ctrl properties failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    // 只有属性改变了才需要执行实际的写属性操作
    on_off = disable ? 1 : 0;

    if (prop.OnOffProperties.copyBackDisabled != on_off) {
        prop.OnOffProperties.copyBackDisabled = on_off;

        // 如果copyBackDisabled为1，表示禁止copyback功能，SMART
        // copyback功能作为copyback的子功能，应该设置为关闭
        if (prop.OnOffProperties.copyBackDisabled) {
            prop.OnOffProperties.SMARTerEnabled = 0;
            prop.OnOffProperties.SSDSMARTerEnabled = 0;
        }

        retval = SetCtrlPropCmd(ctrl_id, &prop);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: SetCtrlDisableCopyBack -> Set ctrl properties failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        }
    } else {
        debug_log(DLOG_DEBUG,
            "smlib LSI: SetCtrlDisableCopyBack -> Setting is same as before, No need to change property\n");
    }

    return retval;
}

/*
 * Description: 设置是否使能指定控制器的S.M.A.R.T CopyBack功能
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlEnableSmartCopyBack(guint32 ctrl_id, guint8 enable)
{
    gint32 retval = SML_SUCCESS;
    MR_CTRL_PROP prop;
    guint8 on_off = 0;

    retval = GetCtrlPropCmd(ctrl_id, &prop);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR,
            "smlib LSI: SetCtrlEnableSmartCopyBack -> Get ctrl properties failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    // 只有属性改变了才需要执行实际的写属性操作
    on_off = enable ? 1 : 0;

    if (prop.OnOffProperties.SMARTerEnabled != on_off) {
        prop.OnOffProperties.SMARTerEnabled = on_off;
        prop.OnOffProperties.SSDSMARTerEnabled = on_off;

        // 如果SMART copyback设置为打开时copyback功能为禁止，则返回错误
        if (prop.OnOffProperties.SMARTerEnabled && prop.OnOffProperties.copyBackDisabled) {
            retval = SML_ERR_CTRL_SET_PROP_UPLEVEL_FUNC_DISABLED;
            debug_log(DLOG_ERROR,
                "smlib LSI: SetCtrlEnableSmartCopyBack -> Attemp to Enable SMART CopyBack while CopyBack disabled, "
                "CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
            return retval;
        }

        retval = SetCtrlPropCmd(ctrl_id, &prop);
        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: SetCtrlEnableSmartCopyBack -> Set ctrl properties failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        }
    } else {
        debug_log(DLOG_DEBUG,
            "smlib LSI: SetCtrlEnableSmartCopyBack -> Setting is same as before, No need to change property\n");
    }

    return retval;
}

/*
 * Description: 设置是否使能指定控制器的JBOD功能(物理盘直通功能)
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlEnableJbod(guint32 ctrl_id, guint8 enable)
{
    gint32 retval = SML_SUCCESS;
    MR_CTRL_PROP prop;
    guint8 on_off = 0;

    retval = GetCtrlPropCmd(ctrl_id, &prop);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_ERROR, "smlib LSI: SetCtrlEnableJbod -> Get ctrl properties failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    // 只有属性改变了才需要执行实际的写属性操作
    on_off = enable ? 1 : 0;

    if (prop.OnOffProperties.enableJBOD != on_off) {
        prop.OnOffProperties.enableJBOD = on_off;
        retval = SetCtrlPropCmd(ctrl_id, &prop);
        if (retval == MFI_STAT_INVALID_SEQUENCE_NUMBER) {
            (void)memset_s(&prop, sizeof(prop), 0, sizeof(prop));
            (void)GetCtrlPropCmd(ctrl_id, &prop);
            if (prop.OnOffProperties.enableJBOD == on_off) {
                return SML_SUCCESS;
            }

            retval = SML_ERR_CTRL_STATUS_INVALID;
        }

        if (SML_SUCCESS != retval) {
            debug_log(DLOG_ERROR,
                "smlib LSI: SetCtrlEnableJbod -> Set ctrl properties failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        }
    } else {
        debug_log(DLOG_DEBUG,
            "smlib LSI: SetCtrlEnableJbod -> Setting is same as before, No need to change property\n");
    }

    return retval;
}

/*
 * Description: 恢复指定控制器的默认设置
 * History: 2016年11月21日   ()  新生成函数
*/
static gint32 SetCtrlRestoreDefault(guint32 ctrl_id)
{
    gint32 retval = SML_SUCCESS;

    retval = SetCtrlFactoryDefaultscmd(ctrl_id);
    if (retval != SML_SUCCESS && retval != SML_ERR_REBOOT_REQUIRED) {
        debug_log(DLOG_ERROR,
            "smlib LSI: SetCtrlRestoreDefault -> Restore Ctrl factory default failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}
/* END:   Added on 2016/11/21 */

/*
 * Description: 查看外部配置（foreign磁盘包含的RAID配置信息）
 */
static gint32 ScanCtrlForeignConfig(guint32 ctrl_id, MR_FOREIGN_CFG_GUIDS *frnGuid)
{
    SL_LIB_CMD_PARAM_T libCmdParam;
    guint8 libType;
    gint32 retval;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    libCmdParam.cmdType = SL_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_SCAN_FOR_FOREIGN_CONFIG;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.pData = frnGuid;
    libCmdParam.dataSize = (guint32)sizeof(MR_FOREIGN_CFG_GUIDS);
    retval = ProcessLibCommandCall(libType, &libCmdParam);

    return retval;
}

/*
 * Description: 导入外部配置（foreign磁盘包含的RAID配置信息）
 */
static gint32 ImportCtrlForeignConfig(guint32 ctrl_id)
{
    SL_LIB_CMD_PARAM_T libCmdParam;
    MR_FOREIGN_CFG_GUIDS frnGuid = {0};
    guint8 libType;
    gint32 retval;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    retval = ScanCtrlForeignConfig(ctrl_id, &frnGuid);
    if (retval != SML_SUCCESS) {
        return retval;
    }
    if (frnGuid.count == 0) {
        debug_log(DLOG_ERROR, "[%s] NO FOREIGN CONFIGS FOUND", __FUNCTION__);
        return SML_ERR_CONFIG_NO_FOREIGN_CONFIG;
    }

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    libCmdParam.cmdType = SL_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_IMPORT_FOREIGN_CONFIG;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.configGUIDRef.GUIDIndex = 0xff; // 0xff all foreign config
    retval = ProcessLibCommandCall(libType, &libCmdParam);

    return retval;
}

/*
 * Description: 清除外部配置（foreign磁盘包含的RAID配置信息）
 */
LOCAL gint32 ClearCtrlForeignConfig(guint32 ctrl_id)
{
    SL_LIB_CMD_PARAM_T libCmdParam;
    MR_FOREIGN_CFG_GUIDS frnGuid = {0};
    gint32 retval;
 
    guint8 libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
 
    retval = ScanCtrlForeignConfig(ctrl_id, &frnGuid);
    if (retval != SML_SUCCESS) {
        return retval;
    }
    if (frnGuid.count == 0) {
        debug_log(DLOG_ERROR, "[%s] NO FOREIGN CONFIGS FOUND", __FUNCTION__);
        return SML_ERR_CONFIG_NO_FOREIGN_CONFIG;
    }
 
    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    libCmdParam.cmdType = SL_CONFIG_CMD_TYPE;
    libCmdParam.cmd = 7; // 7 SL_CLEAR_FOREIGN_CONFIG 清除外部配置
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.configGUIDRef.GUIDIndex = 0xff; // 0xff all foreign config
 
    retval = ProcessLibCommandCall(libType, &libCmdParam);
 
    return retval;
}

/*
 * Description: 执行设置BIOS启动模式的命令
 * History: 2018年5月22日    新生成函数
*/
static gint32 SetCtrlBIOSBootModeCmd(guint32 ctrl_id, guint8 boot_mode)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T lcp;
    SL_DCMD_INPUT_T dcmdInput;
    MR_BIOS_DATA biosData;
    gint32 retval;

    retval = GetBIOSData(ctrl_id, &biosData);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "GetCtrlBiosData : ProcessLibCommandCall failed, retval = 0x%X\n", retval);
        return retval;
    }

    debug_log(DLOG_DEBUG, "GetCtrlBiosData : biosData.continueOnError = %d, would be set to %d\n",
        biosData.continueOnError, boot_mode);

    if (boot_mode == biosData.continueOnError) {
        return SML_SUCCESS;
    }

    (void)memset_s(&lcp, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    biosData.continueOnError = boot_mode;

    dcmdInput.opCode = MR_DCMD_CTRL_BIOS_DATA_SET;
    dcmdInput.flags = SL_DIR_BOTH;
    dcmdInput.dataTransferLength = (guint32)sizeof(MR_BIOS_DATA);
    dcmdInput.pData = &biosData;

    lcp.cmdType = SL_PASSTHRU_CMD_TYPE;
    lcp.cmd = SL_DCMD_PASSTHRU;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)SL_DCMD_INPUT_S;
    lcp.pData = &dcmdInput;

    retval = ProcessLibCommandCall(libType, &lcp);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "SetCtrlBiosData : ProcessLibCommandCall failed, retval = 0x%X\n", retval);
        return retval;
    }

    return retval;
}

/*
 * Description: 转换控制模式到个人控制模式
*/
static gint32 ConvertModetoPersonalityMode(guint8 mode, guint8 *personality_mode)
{
    if (personality_mode == NULL) {
        return SML_ERR_NULL_DATA;
    }

    switch (mode) {
        case CTRL_MODE_RAID:
            *personality_mode = MR_CTRL_PERSONALITY_RAID;
            break;
        case CTRL_MODE_HBA:
            *personality_mode = MR_CTRL_PERSONALITY_HBA;
            break;
        case CTRL_MODE_JBOD:
            *personality_mode = MR_CTRL_PERSONALITY_JBOD;
            break;
        default:
            return SML_ERR_CTRL_PARAM_ILLEGAL;
    }

    return SML_SUCCESS;
}

/*
 Description: 转换支持的工作模式
 */
static void ConvertSupportedMode(MR_CTRL_PERSONALITY_INFO* personality_info, SML_CTRL_OPERATIONS_S* ctrl_operations)
{
    guint8 i;

    for (i = 0; i < GET_ARRAY_ITEMS(personality_info->supportedPersonalities); i++) {
        if (personality_info->supportedPersonalities[i].personality == MR_CTRL_PERSONALITY_UNDEFINED) {
            continue;
        }

        if (personality_info->supportedPersonalities[i].personality == MR_CTRL_PERSONALITY_RAID) {
            ctrl_operations->ctrl_operations.support_raid = 1;
        }

        if (personality_info->supportedPersonalities[i].personality == MR_CTRL_PERSONALITY_HBA) {
            ctrl_operations->ctrl_operations.support_hba = 1;
        }

        if (personality_info->supportedPersonalities[i].personality == MR_CTRL_PERSONALITY_JBOD) {
            ctrl_operations->ctrl_operations.support_jbod = 1;
        }
    }

    return;
}

static gint32 ConvertPersonalityModetoMode(guint8 personality_mode, guint8 *mode)
{
    if (mode == NULL) {
        return SML_ERR_NULL_DATA;
    }

    switch (personality_mode) {
        case MR_CTRL_PERSONALITY_RAID:
            *mode = CTRL_MODE_RAID;
            break;
        case MR_CTRL_PERSONALITY_HBA:
            *mode = CTRL_MODE_HBA;
            break;
        case MR_CTRL_PERSONALITY_JBOD:
            *mode = CTRL_MODE_JBOD;
            break;
        default:
            *mode = 0xff;
    }

    return SML_SUCCESS;
}

/*
 * Description : 调用博通storlib设置控制卡模式
 * Notes：profile_id属性暂时没用到  ，默认用0
*/
static gint32 SetCtrlPersonalityMode(guint32 ctrl_id, SML_CTRL_PERSONALITY_MODE *mode_param)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T lcp;
    SL_DCMD_INPUT_T dcmdInput;
    MR_CTRL_PERSONALITY_INFO MrCtrlPersonalityInfo;
    gint32 retval = 0;
    guint8 personality_mode;

#define CRTL_PERSONALITY_PROFILE_ID_UNKNOWN 0xff

    debug_log(DLOG_DEBUG, "SetCtrlPersonalityMode ctrl_mode %u profile_id %u ", mode_param->mode,
        mode_param->profile_id);

    retval = ConvertModetoPersonalityMode(mode_param->mode, &personality_mode);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "smlib LSI: SetCtrlPersonalityMode failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    (void)memset_s(&lcp, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);
    (void)memset_s(&MrCtrlPersonalityInfo, sizeof(MR_CTRL_PERSONALITY_INFO), 0, sizeof(MR_CTRL_PERSONALITY_INFO));

    dcmdInput.opCode = MR_DCMD_CTRL_PERSONALITY_SET;
    dcmdInput.flags = SL_DIR_WRITE;
    dcmdInput.dataTransferLength = (guint32)sizeof(MR_CTRL_PERSONALITY_INFO);
    dcmdInput.pData = &MrCtrlPersonalityInfo;
    dcmdInput.mbox.s[0] = personality_mode;

    if (mode_param->profile_id != CRTL_PERSONALITY_PROFILE_ID_UNKNOWN) {
        dcmdInput.mbox.s[1] = mode_param->profile_id;
    }

    lcp.cmdType = SL_PASSTHRU_CMD_TYPE;
    lcp.cmd = SL_DCMD_PASSTHRU;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)SL_DCMD_INPUT_S;
    lcp.pData = &dcmdInput;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    retval = ProcessLibCommandCall(libType, &lcp);
    if (retval != SL_SUCCESS && retval != SML_ERR_REBOOT_REQUIRED) {
        debug_log(DLOG_DEBUG, "SetRaidControllerPersonalityMode : ProcessLibCommandCall failed, retval = 0x%X\n",
            retval);
    }

    return retval;
}

/*
 Descripition: 设置控制器的硬盘故障记忆功能
 */
static gint32 SetCtrlMaintainPdFailHistory(guint32 ctrl_id, guint8 enbale)
{
    gint32 ret;
    MR_CTRL_PROP prop = {0};

    ret = GetCtrlPropCmd(ctrl_id, &prop);
    if (ret != SL_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: GetCtrlPropCmd failed, ret = 0x%X.", __FUNCTION__, ret);
        return ret;
    }

    prop.maintainPdFailHistory = enbale;
    ret = SetCtrlPropCmd(ctrl_id, &prop);
    if (ret != SL_SUCCESS) {
        debug_log(DLOG_ERROR, "%s: SetCtrlPropCmd failed, ret = 0x%X.", __FUNCTION__, ret);
    }

    return ret;
}

static gint32 GetCtrlMode(guint32 ctrl_id, guint8 *ctrl_mode, SML_CTRL_OPERATIONS_S* ctrl_operations)
{
    guint8 libType = 0;
    SL_LIB_CMD_PARAM_T lcp;
    SL_DCMD_INPUT_T dcmdInput;
    MR_CTRL_PERSONALITY_INFO MrCtrlPersonalityInfo;
    gint32 retval = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIBIR || libType == SL_LIB_TYPE_STORELIBIR_2 ||
        libType == SL_LIB_TYPE_STORELIBIR_3 || libType == SL_LIB_TYPE_STORELIBIT ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        // IT卡直接返回HBA模式
        *ctrl_mode = CTRL_MODE_HBA;
        ctrl_operations->ctrl_operations.support_hba = 1;
        return SML_SUCCESS;
    }

    (void)memset_s(&lcp, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);
    (void)memset_s(&MrCtrlPersonalityInfo, sizeof(MR_CTRL_PERSONALITY_INFO), 0, sizeof(MR_CTRL_PERSONALITY_INFO));

    dcmdInput.opCode = MR_DCMD_CTRL_PERSONALITY_GET;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.dataTransferLength = (guint32)sizeof(MR_CTRL_PERSONALITY_INFO);
    dcmdInput.pData = &MrCtrlPersonalityInfo;

    lcp.cmdType = SL_PASSTHRU_CMD_TYPE;
    lcp.cmd = SL_DCMD_PASSTHRU;
    lcp.ctrlId = ctrl_id;
    lcp.dataSize = (guint32)SL_DCMD_INPUT_S;
    lcp.pData = &dcmdInput;

    retval = ProcessLibCommandCall(libType, &lcp);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "GetRaidControllerPersonalityMode : ProcessLibCommandCall failed, retval = 0x%X\n",
            retval);
        return retval;
    }

    ConvertSupportedMode(&MrCtrlPersonalityInfo, ctrl_operations);

    debug_log(DLOG_DEBUG, "GetRaidControllerPersonalityMode : val %u", MrCtrlPersonalityInfo.personalityBitmap);

    return ConvertPersonalityModetoMode(MrCtrlPersonalityInfo.personalityBitmap, ctrl_mode);
}

/*
 * Description: 将华为自定义的BIOS启动模式转换为storelib的启动模式定义
 * History: 2018年5月22日    新生成函数
*/
static gint32 ConvertBootModetoSLDefinition(guint8 boot_mode, guint8 *sl_boot_mode)
{
    if (sl_boot_mode == NULL) {
        return SML_ERR_NULL_DATA;
    }

    switch (boot_mode) {
        case CTRL_BIOS_BOOT_MODE_SOE:
            *sl_boot_mode = MR_BOOT_MODE_USER;
            break;
        case CTRL_BIOS_BOOT_MODE_POE:
            *sl_boot_mode = MR_BOOT_MODE_COE;
            break;
        case CTRL_BIOS_BOOT_MODE_IOE:
            *sl_boot_mode = MR_BOOT_MODE_HCOE;
            break;
        case CTRL_BIOS_BOOT_MODE_HSM:
            *sl_boot_mode = MR_BOOT_MODE_HSM;
            break;
        default:
            return SML_ERR_CTRL_PARAM_ILLEGAL;
    }

    return SML_SUCCESS;
}

/*
 * Description: 设置控制器BIOS启动模式
 * History: 2018年5月22日    新生成函数
*/
static gint32 SetCtrlBIOSBootMode(guint32 ctrl_id, guint8 boot_mode)
{
    gint32 retval = SML_SUCCESS;
    guint8 sl_boot_mode = 0;

    retval = ConvertBootModetoSLDefinition(boot_mode, &sl_boot_mode);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_DEBUG, "smlib LSI: ConvertBootModetoSLDefinition failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    retval = SetCtrlBIOSBootModeCmd(ctrl_id, sl_boot_mode);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_DEBUG, "smlib LSI: SetCtrlBIOSBootModeCmd failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}

/*
 * Description: 将storelib的启动模式定义转换为华为自定义的BIOS启动模式
*/
static gint32 ConvertBootModetoHWDefinition(guint8 sl_boot_mode, guint8 *boot_mode)
{
    if (NULL == boot_mode) {
        return SML_ERR_NULL_DATA;
    }

    switch (sl_boot_mode) {
        case MR_BOOT_MODE_USER:
            *boot_mode = CTRL_BIOS_BOOT_MODE_SOE;
            break;
        case MR_BOOT_MODE_COE:
            *boot_mode = CTRL_BIOS_BOOT_MODE_POE;
            break;
        case MR_BOOT_MODE_HCOE:
            *boot_mode = CTRL_BIOS_BOOT_MODE_IOE;
            break;
        case MR_BOOT_MODE_HSM:
            *boot_mode = CTRL_BIOS_BOOT_MODE_HSM;
            break;
        default:
            return SML_ERR_CTRL_PARAM_ILLEGAL;
    }

    return SML_SUCCESS;
}

/*
 * Description: 执行获取控制器BIOS启动模式的命令
*/
static gint32 GetCtrlBIOSBootMode(guint32 ctrl_id, guint8 *boot_mode)
{
    MR_BIOS_DATA biosData;
    gint32 retval;
    guint8 sl_boot_mode;

    if (NULL == boot_mode) {
        return SML_ERR_NULL_DATA;
    }

    retval = GetBIOSData(ctrl_id, &biosData);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "GetCtrlBiosData : ProcessLibCommandCall failed, retval = 0x%X\n", retval);
        return retval;
    }

    sl_boot_mode = biosData.continueOnError;

    debug_log(DLOG_DEBUG, "GetCtrlBiosData : biosData.continueOnError = %d\n", sl_boot_mode);

    retval = ConvertBootModetoHWDefinition(sl_boot_mode, boot_mode);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_DEBUG, "smlib LSI: ConvertBootModetoHWDefinition failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    return SML_SUCCESS;
}

/*
 * Description: 对物理盘Eid为0xffff(3008 IT接直通背板上的硬盘)进行转换处理，
 *              因为0xffff为无效值，直接使用会导致无法区分物理盘未识别和识别后Eid为0xffff的情况
 *              这里将其转换为其他合适的数值，SML向上层只报转换过的Eid值
*/
static gint32 ConvertDirectAttachedPdEid(MR_PD_LIST *pPdList, guint16 *pCovertedEid)
{
    volatile guint32 idx = 0;
    guint8 direct_attached_eid_found = 0, eid_conflicted = 0;
    guint16 eid_count = 0;
    guint16 pd_eids[SML_MAX_PHYSICAL_DRIVES] = { 0 };
    guint16 converted_eid = PD_EID_NOT_IN_ENCLOSURE;
    guint32 i = 0;

    if (NULL == pPdList || NULL == pCovertedEid) {
        return FALSE;
    }

    *pCovertedEid = PD_EID_NOT_IN_ENCLOSURE;

    pPdList->count = (pPdList->count > MAX_PHYSICAL_DEVICES) ? MAX_PHYSICAL_DEVICES : pPdList->count;
    // 确定是否存在0xffff这个特殊的Eclosure ID，同时获取保存Eid的列表
    for (idx = 0; idx < pPdList->count; idx++) {
        // 只获取PD=Disk的deviceId和slot number
        if (SPC_HARDDISK == pPdList->addr[idx].scsiDevType) {
            if (PD_EID_NOT_IN_ENCLOSURE == pPdList->addr[idx].enclDeviceId) {
                direct_attached_eid_found = 1;
            }
            pd_eids[eid_count] = pPdList->addr[idx].enclDeviceId;

            eid_count++;
            if (eid_count >= SML_MAX_PHYSICAL_DRIVES) {
                break;
            }
        }
    }

    // 不存在0xffff Eid，直接返回FALSE
    if (0 == direct_attached_eid_found) {
        return FALSE;
    }

    // 转换Eid为0xffff - 1
    converted_eid = PD_EID_NOT_IN_ENCLOSURE - 1;
    // 如果转换后的Eid和现有的Eid冲突，则尝试另外1个Eid
    for (i = 0; i < PD_EID_CONVERT_RETRY_MAX; i++) {
        eid_conflicted = 0;
        for (idx = 0; idx < eid_count; idx++) {
            if (converted_eid == pd_eids[idx]) {
                eid_conflicted = 1;
                break;
            }
        }
        // 没有冲突，直接退出
        if (0 == eid_conflicted) {
            break;
        }

        // 冲突，转换的Eid减1，重新验证是否冲突
        converted_eid--;
    }

    // 达到最大重试次数，还是冲突，返回FALSE
    if (PD_EID_CONVERT_RETRY_MAX == i) {
        return FALSE;
    }

    *pCovertedEid = converted_eid;

    return TRUE;
}
/* END:   Added on 2017/12/18 */

/*
 * Description: 模拟插入RAID卡事件
 * History: 2019年1月9日    新生成函数
*/
gint32 lsi_mock_insert_ctrl_event(guint32 ctrl_id, gpointer data)
{
    gint32 ret = SML_SUCCESS;
    SML_MOCK_CTRL_EVENT_S *mock_event = (SML_MOCK_CTRL_EVENT_S *)data;

    ret = MockInsertCtrlEvent(ctrl_id, mock_event);

    return ret;
}

/*
 * Description: OS下电或重启时清除RAID卡诊断事件
 * History: 2019年2月27日    新生成函数
*/
gint32 lsi_clear_ctrl_diag_event(guint32 ctrl_id)
{
    ClearCtrlDiagEvent(ctrl_id);
    return SML_SUCCESS;
}

/*
 * Description: 更新LSI的storelib中的缓存数据
 * History: 2017年6月1日    新生成函数
*/
gint32 lsi_update_ctrl_cache(guint32 ctrl_id)
{
    guint8 libType = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIB) {
        ;
    } else if (libType == SL_LIB_TYPE_STORELIBIR) {
        ;
    } else if (libType == SL_LIB_TYPE_STORELIBIR_2) {
        ;
    } else if ((libType == SL_LIB_TYPE_STORELIBIR_3) || (libType == SL_LIB_TYPE_STORELIBIT) ||
        (libType == SL_LIB_TYPE_STORELIBCUSTOM)) {
    } else if ((libType == SL_LIB_TYPE_STORELIBIR_3) || (libType == SL_LIB_TYPE_STORELIBIT)) {
        UpdateCtrlCacheInStorelib(ctrl_id);
    }

    return SML_SUCCESS;
}

/*
 * Description: 获取控制器的SAS速率, 同时支持多个时，取速率最高的
 * History: 2019年8月26日   新生成函数
*/
static guint8 GetCtrlPDInterface(const MR_CTRL_INFO *pCtrlInfo)
{
    if (pCtrlInfo == NULL) {
        return CTRL_DEVICE_INTERFACE_INVALID;
    } else if (pCtrlInfo->deviceInterface.SAS_12G) {
        return CTRL_DEVICE_INTERFACE_SAS_12G;
    } else if (pCtrlInfo->deviceInterface.SAS_6G) {
        return CTRL_DEVICE_INTERFACE_SAS_6G;
    } else if (pCtrlInfo->deviceInterface.SAS_3G) {
        return CTRL_DEVICE_INTERFACE_SAS_3G;
    } else if (pCtrlInfo->deviceInterface.SATA_3G) {
        return CTRL_DEVICE_INTERFACE_SATA_3G;
    } else if (pCtrlInfo->deviceInterface.SATA_1_5G) {
        return CTRL_DEVICE_INTERFACE_SATA_1_5G;
    } else if (pCtrlInfo->deviceInterface.SPI) {
        return CTRL_DEVICE_INTERFACE_SPI;
    } else {
        return CTRL_DEVICE_INTERFACE_INVALID;
    }
}

/*
 * Description : 获取控制器温度 封装函数减少复杂度 255为控制器温度无效值
*/
static guint8 GetCtrlTemp(const MR_CTRL_INFO *pCtrlInfo)
{
    if (pCtrlInfo == NULL) {
        return INVALID_CONTROLLER_TEMP_VALUE;
    } else if (pCtrlInfo->hwPresent.tempSensorROC) {
        return pCtrlInfo->temperatureROC;
    } else if (pCtrlInfo->hwPresent.tempSensorCtrl) {
        return pCtrlInfo->temperatureCtrl;
    }

    return INVALID_CONTROLLER_TEMP_VALUE;
}

static gint32 SetCtrlProppertyOperations(guint32 ctrl_id, guint8 operation, gpointer param, guint32 param_length)
{
    guint8 enable = 0, disable = 0, boot_mode = 0;
    SML_CTRL_PERSONALITY_MODE *mode_param = NULL;
    gint32 retval;

    switch (operation) {
        case CTRL_OPERATION_DISABLE_COPYBACK:
            disable = *(guint8 *)param;
            retval = SetCtrlDisableCopyBack(ctrl_id, disable);
            break;

        case CTRL_OPERATION_ENABLE_SMART_COPYBACK:
            enable = *(guint8 *)param;
            retval = SetCtrlEnableSmartCopyBack(ctrl_id, enable);
            break;

        case CTRL_OPERATION_ENABLE_JBOD:
            enable = *(guint8 *)param;
            retval = SetCtrlEnableJbod(ctrl_id, enable);
            break;

        case CTRL_OPERATION_SET_BIOS_BOOT_MODE:
            boot_mode = *(guint8 *)param;
            retval = SetCtrlBIOSBootMode(ctrl_id, boot_mode);
            break;

        case CTRL_OPERATION_SET_PERSONALITY_MODE:
            if (param_length != sizeof(SML_CTRL_PERSONALITY_MODE)) {
                return SML_ERR_NULL_DATA;
            }
            mode_param = (SML_CTRL_PERSONALITY_MODE *)param;
            retval = SetCtrlPersonalityMode(ctrl_id, mode_param);
            break;

        case CTRL_OPERATION_SET_MAINTAIN_PDFAIL_HISTORY:
            enable = *(guint8 *)param;
            retval = SetCtrlMaintainPdFailHistory(ctrl_id, enable);
            break;

        default:
            retval = SML_ERR_CTRL_OPERATION_NOT_SUPPORT;
            break;
    }

    return retval;
}

static void get_static_info(SML_CTRL_BASIC_INFO_S *ctrl, MR_CTRL_INFO *CtrlInfo)
{
    ctrl->ld_present_conut = CtrlInfo->ldPresentCount;
    ctrl->ld_degraded_count = CtrlInfo->ldDegradedCount;
    ctrl->ld_offline_count = CtrlInfo->ldOfflineCount;
    ctrl->pd_present_count = CtrlInfo->pdPresentCount;
    ctrl->pddisk_present_count = CtrlInfo->pdDiskPresentCount;
    ctrl->pddisk_prefail_count = CtrlInfo->pdDiskPredFailureCount;
    ctrl->pddisk_fail_count = CtrlInfo->pdDiskFailedCount;
}

static void get_memory_info(guint32 ctrl_id, SML_CTRL_BASIC_INFO_S *ctrl, MR_CTRL_INFO *CtrlInfo)
{
    ctrl->memory_size = CtrlInfo->memorySize;
    ctrl->memory_ce_count = CtrlInfo->memCorrectableErrorCount;
    ctrl->memory_uce_count = CtrlInfo->memUnCorrectableErrorCount;
    ctrl->memory_ecc_count = CtrlInfo->eccBucketCount;
    ctrl->memory_ecc_bucket_size = CtrlInfo->properties.eccBucketSize;
    debug_log(DLOG_DEBUG,
        "smlib: LSI:GetCtrlInfo Controller#%d Memory CE = %d, UCE = %d, ECC Count/ECC Bucket Size = %d/%d\n",
        SML_CTRL_ID_VALID_BIT(ctrl_id), ctrl->memory_ce_count, ctrl->memory_uce_count, ctrl->memory_ecc_count,
        ctrl->memory_ecc_bucket_size);
}

/*
 * Description: 获取与配置相关允许的操作
 */
static gint32 GetConfigAllowedOperation(guint32 ctrl_id, SL_CONFIG_ALLOWED_OPER_T *config_allowed_oper)
{
    SL_LIB_CMD_PARAM_T libCmdParam;

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);

    guint8 libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    libCmdParam.cmdType = SL_CONFIG_CMD_TYPE;
    libCmdParam.cmd = SL_GET_CONFIG_ALLOWED_OPERATION;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)SL_CONFIG_ALLOWED_OPER_S;
    libCmdParam.pData = config_allowed_oper;

    return ProcessLibCommandCall(libType, &libCmdParam);
}

/*
 * Description: 获取控制器支持的操作
 */
static void get_ctrl_support_operation(SML_CTRL_BASIC_INFO_S *ctrl, MR_CTRL_INFO *ctrl_info)
{
    ctrl->operations.pd_operations.support_temperature = ctrl_info->pdOperations.supportTemperature;
    ctrl->operations.pd_operations.support_crypto_erase = ctrl_info->pdOperations.supportCryptoErase;

    // 0x0 = FW doesnt support personality change (get and set)
    // 0x1 = FW supports personality change between the supported modes
    // 0x2 = FW supports personality get, set not possible
    // 0x3 = reserved
    ctrl->operations.ctrl_operations.support_mode_set =
        ctrl_info->adapterOperations3.supportPersonalityChange == 1 ? 1 : 0;
    ctrl->operations.ctrl_operations.support_jbod_state = ctrl_info->adapterOperations2.supportJBOD;
    ctrl->operations.ctrl_operations.configured_drive_wcp = CTRL_DRIVE_WCP_INVALID;
    ctrl->operations.ctrl_operations.unconfigured_drive_wcp = CTRL_DRIVE_WCP_INVALID;
    ctrl->operations.ctrl_operations.hba_drive_wcp = CTRL_DRIVE_WCP_INVALID;
    ctrl->operations.ld_operations.support_read_policy = ctrl_info->ldOperations.readPolicy;
    ctrl->operations.ld_operations.support_write_policy = ctrl_info->ldOperations.writePolicy;
    ctrl->operations.ld_operations.support_io_policy = ctrl_info->ldOperations.ioPolicy;
    ctrl->operations.ld_operations.support_access_policy = ctrl_info->ldOperations.accessPolicy;
    ctrl->operations.ld_operations.support_disk_cache_policy = ctrl_info->ldOperations.diskCachePolicy;

    return;
}

/*
 * Description: 获取为逻辑盘创建过程中需要的控制器信息
 */
static void get_ctrl_info_for_ld_creation(SML_CTRL_BASIC_INFO_S *ctrl, MR_CTRL_INFO *ctrl_info)
{
    ctrl->max_lds_per_array = ctrl_info->maxLdsPerArray;
    ctrl->max_lds = ctrl_info->maxLDs;

    ctrl->allow_mix_ssd_hdd = ctrl_info->pdMixSupport.allowMixSSDHDDInLD;
    ctrl->allow_ssd_mix = ctrl_info->pdMixSupport.allowSSDMixInLD;

    ctrl->raid0_supported = ctrl_info->raidLevels.raidLevel_0;
    ctrl->raid1_supported = ctrl_info->raidLevels.raidLevel_1;
    ctrl->raid5_supported = ctrl_info->raidLevels.raidLevel_5;
    ctrl->raid6_supported = ctrl_info->raidLevels.raidLevel_6;
    ctrl->raid10_supported = ctrl_info->raidLevels.raidLevel_10;
    ctrl->raid50_supported = ctrl_info->raidLevels.raidLevel_50;
    ctrl->raid60_supported = ctrl_info->raidLevels.raidLevel_60;

    ctrl->ssc_raid0_unsupported = ctrl_info->raidLevels.SSCraidLevel_0_unsupported;
    ctrl->ssc_raid1_supported = ctrl_info->raidLevels.SSCraidLevel_1;
    ctrl->ssc_raid5_supported = ctrl_info->raidLevels.SSCraidLevel_5;

    ctrl->min_pd_raid0 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_0;
    ctrl->min_pd_raid1 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_1;
    ctrl->min_pd_raid5 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_5;
    ctrl->min_pd_raid6 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_6;
    ctrl->min_pd_raid10 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_10;
    ctrl->min_pd_raid50 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_50;
    ctrl->min_pd_raid60 = ctrl_info->pdsForRaidLevels.minPdRaidLevel_60;

    ctrl->max_pd_raid0 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_0;
    ctrl->max_pd_raid1 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_1;
    ctrl->max_pd_raid5 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_5;
    ctrl->max_pd_raid6 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_6;
    ctrl->max_pd_raid10 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_10;
    ctrl->max_pd_raid50 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_50;
    ctrl->max_pd_raid60 = ctrl_info->pdsForRaidLevels.maxPdRaidLevel_60;

    return;
}

/*
 * Description: 获取默认写策略
 */
static void get_default_wp(guint32 ctrl_id, SML_CTRL_BASIC_INFO_S *ctrl)
{
    MR_MFC_DEFAULTS mfc_default;

    if (LSI_STORELIB_TYPE_VALID_BIT(ctrl_id) != SL_LIB_TYPE_STORELIB) {
        return;
    }

    (void)memset_s(&mfc_default, sizeof(mfc_default), 0, sizeof(mfc_default));

    if (GetCtrlMFCDefault(ctrl_id, &mfc_default) != SL_SUCCESS) {
        return;
    }

    if (mfc_default.writeBack == MR_LD_CACHE_POLICY_WRITE_THROUGH) {
        ctrl->operations.ld_operations.default_write_policy = LD_CACHE_WRITE_THROUGH;
    } else if (mfc_default.writeBack == MR_LD_CACHE_POLICY_WRITE_BACK) {
        ctrl->operations.ld_operations.default_write_policy = LD_CACHE_WRITE_BACK;
    } else {
        ctrl->operations.ld_operations.default_write_policy = LD_CACHE_WRITE_BUTT;
    }

    return;
}

/*
 * Description: 不支持的字段，赋无效值
 */
static void set_ctrl_properties_unsupported(SML_CTRL_BASIC_INFO_S *ctrl)
{
    ctrl->spare_activation_mode = STORAGE_INFO_INVALID_BYTE;
    ctrl->nobattery_write_cache = STORAGE_INFO_INVALID_BYTE;
    ctrl->read_cache_percent = STORAGE_INFO_INVALID_BYTE;
    ctrl->pcie_link_width = STORAGE_INFO_INVALID_BYTE;
    return;
}

/*
 * Description: 通过LSI storelib获取RAID卡的信息
 * History: 2016年3月7日    新生成函数
*/
gint32 lsi_get_ctrl_info(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    guint8 idx = 0, max_count, mode;
    MR_CTRL_INFO CtrlInfo;
    errno_t safe_fun_ret = EOK;
    SL_CONFIG_ALLOWED_OPER_T config_allowed_oper;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    SML_CTRL_BASIC_INFO_S *ctrl = (SML_CTRL_BASIC_INFO_S *)data;

    (void)memset_s(&CtrlInfo, sizeof(MR_CTRL_INFO), 0, sizeof(MR_CTRL_INFO));

    retval = GetCtrlInfo(ctrl_id, &CtrlInfo);
    if (retval != SML_SUCCESS) {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlInfo failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }

    if (CtrlInfo.imageComponentCount > (sizeof(CtrlInfo.imageComponent) / sizeof(CtrlInfo.imageComponent[0]))) {
        max_count = (guint8)(sizeof(CtrlInfo.imageComponent) / sizeof(CtrlInfo.imageComponent[0]));
    } else {
        max_count = CtrlInfo.imageComponentCount;
    }

    for (idx = 0; idx < max_count; idx++) {
        // RAID控制器的固件版本(APP)
        if (0 == strncasecmp(CtrlInfo.imageComponent[idx].name, "APP", strlen("APP"))) {
            safe_fun_ret = memcpy_s(ctrl->fw_version, sizeof(ctrl->fw_version), CtrlInfo.imageComponent[idx].version,
                sizeof(CtrlInfo.imageComponent[idx].version));
            if (safe_fun_ret != EOK) {
                debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            }
            continue;
        }

        // RAID控制器的配置版本(NVDATA)
        if (0 == strncasecmp(CtrlInfo.imageComponent[idx].name, "NVDT", strlen("NVDT")) ||
            0 == strncasecmp(CtrlInfo.imageComponent[idx].name, "NVDATA", strlen("NVDATA"))) {
            safe_fun_ret = memcpy_s(ctrl->nvdata_version, sizeof(ctrl->nvdata_version),
                CtrlInfo.imageComponent[idx].version, sizeof(CtrlInfo.imageComponent[idx].version));
            if (safe_fun_ret != EOK) {
                debug_log(DLOG_ERROR, "%s: memcpy_s fail, ret = %d\n", __FUNCTION__, safe_fun_ret);
            }
            continue;
        }
    }

    // LD和PD的总体统计情况
    get_static_info(ctrl, &CtrlInfo);

    // RAID控制器内存信息
    get_memory_info(ctrl_id, ctrl, &CtrlInfo);

    ctrl->device_interface = GetCtrlPDInterface(&CtrlInfo);
    ctrl->cache_pinned = CtrlInfo.adapterStatus.cacheIsPinned;
    ctrl->maint_pd_fail_history = (CtrlInfo.properties.maintainPdFailHistory) ? TRUE : FALSE;

    ctrl->properties.copyback_enabled = !(CtrlInfo.properties.OnOffProperties.copyBackDisabled);
    ctrl->properties.smarter_copyback_enabled = CtrlInfo.properties.OnOffProperties.SMARTerEnabled;
    ctrl->properties.jbod_enabled = CtrlInfo.properties.OnOffProperties.enableJBOD;
    ctrl->min_strip =
        LSI_STORELIB_TYPE_VALID_BIT(ctrl_id) != SL_LIB_TYPE_STORELIB ? 0xFF : CtrlInfo.stripeSizeOptions.min;
    ctrl->max_strip =
        LSI_STORELIB_TYPE_VALID_BIT(ctrl_id) != SL_LIB_TYPE_STORELIB ? 0xFF : CtrlInfo.stripeSizeOptions.max;

    get_ctrl_support_operation(ctrl, &CtrlInfo);

    (void)strncpy_s(ctrl->ctrl_name, sizeof(ctrl->ctrl_name), CtrlInfo.productName, sizeof(CtrlInfo.productName));
    strncpy_s(ctrl->ctrl_sn, sizeof(ctrl->ctrl_sn), CtrlInfo.serialNo, sizeof(CtrlInfo.serialNo) - 1);

    // 以下为逻辑盘创建过程中需要的控制器信息
    get_ctrl_info_for_ld_creation(ctrl, &CtrlInfo);

    ctrl->ctrl_temp = GetCtrlTemp(&CtrlInfo);

    // 获取控制器模式
    if (GetCtrlMode(ctrl_id, &mode, &ctrl->operations) == SL_SUCCESS) {
        ctrl->mode = mode;
    }

    (void)memset_s(&config_allowed_oper, sizeof(config_allowed_oper), 0, sizeof(config_allowed_oper));
    if (GetConfigAllowedOperation(ctrl_id, &config_allowed_oper) == SL_SUCCESS) {
        ctrl->operations.ctrl_operations.support_epd = config_allowed_oper.makeEPD;
    }

    //  获取默认写策略
    get_default_wp(ctrl_id, ctrl);
    set_ctrl_properties_unsupported(ctrl);
    return retval;
}

/*
 * Description: 通过LSI storelib获取RAID卡的SAS地址
 * History: 2016年3月7日    新生成函数
*/
gint32 lsi_get_ctrl_sas_addr(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;
    MR_MFC_DEFAULTS CtrlMfcDefault;
    SML_SAS_ADDR_S *ctrl = NULL;
    // 代码检视，变量放在函数开头统一定义
    MR_CTRL_INFO CtrlInfo;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    ctrl = (SML_SAS_ADDR_S *)data;
    (void)memset_s(&CtrlMfcDefault, sizeof(MR_MFC_DEFAULTS), 0, sizeof(MR_MFC_DEFAULTS));

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIB) {
        // 获取MFC配置，读取SAS地址
        retval = GetCtrlMFCDefault(ctrl_id, &CtrlMfcDefault);
        if (SML_SUCCESS == retval) {
            format_sas_addr(CtrlMfcDefault.sasAddr, ctrl->addr, sizeof(ctrl->addr));
        } else {
            debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlMFCDefault failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        }
    } else if ((libType == SL_LIB_TYPE_STORELIBIR_3) || (libType == SL_LIB_TYPE_STORELIBIT) ||
        (libType == SL_LIB_TYPE_STORELIBCUSTOM)) {
        (void)memset_s(&CtrlInfo, sizeof(MR_CTRL_INFO), 0, sizeof(MR_CTRL_INFO));

        retval = GetCtrlInfo(ctrl_id, &CtrlInfo);
        if (SML_SUCCESS == retval) {
            format_sas_addr(CtrlInfo.hostInterface.portAddr[0], ctrl->addr, sizeof(ctrl->addr));
        } else {
            debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlInfo failed, CtrlId = %d, return 0x%0x\n",
                SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        }
    } else {
        retval = SML_ERR_INVALID_CMD;
    }

    return retval;
}

/*
 * Description: 通过LSI storelib获取RAID卡的PHY错误统计
 * History: 2016年3月7日    新生成函数
*/
gint32 lsi_get_ctrl_phy_err_count(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    gint32 retval1 = SML_SUCCESS;
    guint32 idx = 0;
    MR_SAS_PHY_CONNECTIONS phyConnections;
    SML_SASPHY_INFO_S *ctrl = NULL;
    // 代码检视，变量放在函数开头统一定义
    MPI2_CONFIG_PAGE_SAS_PHY_1 sasPhy1;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    ctrl = (SML_SASPHY_INFO_S *)data;
    (void)memset_s(&phyConnections, sizeof(phyConnections), 0, sizeof(phyConnections));

    if (SML_SUCCESS == (retval = GetCtrlPhyConnectionsInfo(ctrl_id, &phyConnections))) {
        if (phyConnections.count >= SML_MAX_SAS_PHY_PER_CTRL) {
            ctrl->phy_count = SML_MAX_SAS_PHY_PER_CTRL;
        } else {
            ctrl->phy_count = phyConnections.count;
        }

        for (idx = 0; idx < ctrl->phy_count; idx++) {
            (void)memset_s(&sasPhy1, sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1), 0, sizeof(MPI2_CONFIG_PAGE_SAS_PHY_1));

            retval1 = GetConfigPageInfo(ctrl_id, idx, &sasPhy1);
            if (SML_SUCCESS == retval1) {
                ctrl->phy_err[idx].invalid_dword_count = sasPhy1.InvalidDwordCount;
                ctrl->phy_err[idx].loss_dword_sync_count = sasPhy1.LossDwordSynchCount;
                ctrl->phy_err[idx].phy_reset_problem_count = sasPhy1.PhyResetProblemCount;
                ctrl->phy_err[idx].running_disparity_error_count = sasPhy1.RunningDisparityErrorCount;
            } else {
                debug_log(DLOG_DEBUG, "smlib: LSI:GetConfigPageInfo failed, CtrlId = %d, phy idx = %d, return 0x%0x\n",
                    SML_CTRL_ID_VALID_BIT(ctrl_id), idx, retval1);
            }

            vos_task_delay(200);
        }
    } else {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlPhyConnectionsInfo failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}
/*
 * Description: 获取RAID卡下的Expander的单个PHY错误统计
 */
gint32 lsi_get_exp_phy_err_count(guint32 ctrl_id, gpointer data)
{
    SL_SMP_RESPONSE_REPORT_PHY_ERROR_LOG_T smp_response;
    SML_SASPHY_ERR_INFO_S *phy_err = NULL;
    guint32 tmp = 0;
    gint32 ret;

    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    phy_err = (SML_SASPHY_ERR_INFO_S *)data;
    (void)memset_s(&smp_response, sizeof(smp_response), 0, sizeof(smp_response));
    ret = GetExpSinglePhyErrCount(ctrl_id, phy_err->phy_id, phy_err->exp_sas_addr, &smp_response);
    if (ret != SML_SUCCESS) {
        return ret;
    }

    /* 获取的phy误码数据需要转换大小端 */
    swapBytes((void *)&smp_response.invalidDwordCount, (void *)&tmp, sizeof(smp_response.invalidDwordCount));
    phy_err->phy_err_count.invalid_dword_count = tmp;
    swapBytes((void *)&smp_response.runningDisparityErrorCount, (void *)&tmp,
        sizeof(smp_response.runningDisparityErrorCount));
    phy_err->phy_err_count.running_disparity_error_count = tmp;
    swapBytes((void *)&smp_response.lossDwordSyncCount, (void *)&tmp, sizeof(smp_response.lossDwordSyncCount));
    phy_err->phy_err_count.loss_dword_sync_count = tmp;
    swapBytes((void *)&smp_response.phyResetProblemCount, (void *)&tmp, sizeof(smp_response.phyResetProblemCount));
    phy_err->phy_err_count.phy_reset_problem_count = tmp;

    return ret;
}

/*
 * Description: 获取RAID卡的拓扑信息
 */
gint32 lsi_get_ctrl_exp_list(guint32 ctrl_id, gpointer data)
{
    SML_CTRL_EXP_LIST_INFO_S *exp_list = NULL;
    SL_LIST_ELEMENT_T sas_addr_list[MAX_PHYSICAL_DEVICES];
    void *topology_buffer = NULL;
    gint32 ret;

    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }
    exp_list = (SML_CTRL_EXP_LIST_INFO_S *)data;

    topology_buffer = g_malloc0(SL_TOPOLOGY_BUFFER_SIZE);
    if (topology_buffer == NULL) {
        debug_log(DLOG_DEBUG, "%s allocate memory fail", __FUNCTION__);
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    /* 获取拓扑信息 */
    ret = GetTopologyInfo(ctrl_id, SL_TOPOLOGY_BUFFER_SIZE, topology_buffer);
    if (ret != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "%s fail, ctrl_id=%d, ret=%d", __FUNCTION__, ctrl_id, ret);
        g_free(topology_buffer);
        return ret;
    }

    (void)memset_s(sas_addr_list, sizeof(sas_addr_list), 0, sizeof(sas_addr_list));
    /* 从拓扑中得到Expander的SAS地址列表 */
    BuildSasAddrList(topology_buffer, SL_TOPOLOGY_BUFFER_SIZE, sas_addr_list, &exp_list->count);
    g_free(topology_buffer);

    /* 判断Expander数量是否为0 */
    if (exp_list->count == 0) {
        debug_log(DLOG_DEBUG, "Get RAID Expander SAS Addr Count is 0, ctrl_id=%d", ctrl_id);
        return SML_ERR_EXP_NO_EXPANDER;
    }

    /* 判断Expander数量是否超过了限制 */
    if (exp_list->count > SML_MAX_EXPANDER_PER_CONTROLLER) {
        debug_log(DLOG_DEBUG, "Get RAID Expander Num %d greater than %d, ctrl_id=%d", exp_list->count,
            SML_MAX_EXPANDER_PER_CONTROLLER, ctrl_id);
        exp_list->count = SML_MAX_EXPANDER_PER_CONTROLLER;
    }

    for (gint32 i = 0; i < exp_list->count; i++) {
        if (sas_addr_list[i].deviceType == SL_END_DEVICE) {
            continue;
        }

        /* 如果获取的Expander的phy数量为0，说明RAID卡的fw可能为老版本的 */
        if (sas_addr_list[i].numPhy == 0) {
            ret = SML_ERR_EXP_NO_PHY;
            break;
        }
        /* 排除Expander的虚拟phy，不获取误码信息 */
        exp_list->phy_count_list[i] = sas_addr_list[i].numPhy - sas_addr_list[i].numVirtualPhy;
        /* 判断phy数量是否超过了限制 */
        if (exp_list->phy_count_list[i] > SML_MAX_SAS_PHY_PER_EXPANDER) {
            debug_log(DLOG_DEBUG, "Get RAID Expander Phy Num %d greater than %d, ctrl_id=%d, expander_id=%d",
                exp_list->phy_count_list[i], SML_MAX_SAS_PHY_PER_EXPANDER, ctrl_id, i);
            exp_list->phy_count_list[i] = SML_MAX_SAS_PHY_PER_EXPANDER;
        }
        exp_list->sas_addr_list[i] = sas_addr_list[i].sasAddr;
    }

    return ret;
}

/*
 * Description: 通过LSI storelib获取RAID卡下的Expander的PHY错误统计
 * History: 2018年10月31日    新生成函数  AR.SR.SFEA02130924.009.011
            2021年4月8日      功能由新增的lsi_get_ctrl_exp_list和lsi_get_exp_phy_err_count替代，此函数为保证版本兼容，需要保留
*/
gint32 lsi_get_ctrl_exp_phy_err_count(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    SML_CTRL_EXP_SASPHY_INFO_S *expander = NULL;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    expander = (SML_CTRL_EXP_SASPHY_INFO_S *)data;

    retval = GetExpanderPhyErrorLog(ctrl_id, expander);

    return retval;
}

/*
 * Description: 通过LSI storelib获取RAID卡的BBU状态
 * History: 2016年3月7日    新生成函数
 *          2016年6月25日
 *          并且强制返回成功，避免影响上层处理
*/
gint32 lsi_get_ctrl_bbu_status(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    MR_BBU_STATUS BBUStatus;
    SML_BBU_STATUS_S *ctrl = NULL;
    // 代码检视，变量放在函数开头统一定义
    MR_BBU_DESIGN_INFO bbuDesign;

    guint8 libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIBIR || libType == SL_LIB_TYPE_STORELIBIR_2 ||
        libType == SL_LIB_TYPE_STORELIBIR_3 || libType == SL_LIB_TYPE_STORELIBIT ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        return SML_SUCCESS;
    }

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    ctrl = (SML_BBU_STATUS_S *)data;
    (void)memset_s(&BBUStatus, sizeof(MR_BBU_STATUS), 0, sizeof(MR_BBU_STATUS));

    // TFM卡在位，电容不在位(Pack Missing)，storelib会返回BBU不在位，
    // 因此，为了获取Pack missing这种状态，无论BBU是否在位，都读取BBU的状态
    retval = GetCtrlBBUStatus(ctrl_id, &BBUStatus);
    if (retval != SML_SUCCESS) {
        strncpy_s(ctrl->type, sizeof(ctrl->type), "N/A", strlen("N/A"));
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlBBUStatus failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return SML_SUCCESS;
    }

    if ((BBUStatus.batteryType > MR_BBU_TYPE_iBBU08) ||
        (BBUStatus.batteryType == MR_BBU_TYPE_iBBU08 && BBUStatus.subType != 0)) {
        (void)memset_s(&bbuDesign, sizeof(MR_BBU_DESIGN_INFO), 0, sizeof(MR_BBU_DESIGN_INFO));
        retval = GetCtrlBBUDegsinInfo(ctrl_id, &bbuDesign);
        if (SML_SUCCESS == retval) {
            (void)strncpy_s(ctrl->type, sizeof(ctrl->type), (gchar *)bbuDesign.deviceName,
                sizeof(bbuDesign.deviceName));
        } else {
            strncpy_s(ctrl->type, sizeof(ctrl->type), "Unknown", strlen("Unknown"));
        }
    } else {
        switch (BBUStatus.batteryType) {
            case MR_BBU_TYPE_IBBU:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "IBBU", strlen("IBBU"));
                break;
 
            case MR_BBU_TYPE_BBU:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "BBU", strlen("BBU"));
                break;
 
            case MR_BBU_TYPE_ZCR_LEGACY:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "ZCR Legacy BBU", strlen("ZCR Legacy BBU"));
                break;
 
            case MR_BBU_TYPE_iTBBU3:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "ITBBU3", strlen("ITBBU3"));
                break;
 
            case MR_BBU_TYPE_iBBU08:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "IBBU08", strlen("IBBU08"));
                break;
 
            default:
                strncpy_s(ctrl->type, sizeof(ctrl->type), "Unknown", strlen("Unknown"));
        }
    }

    MR_BBU_FW_STATUS *bbu_fw_status = (MR_BBU_FW_STATUS *)((void *)(&BBUStatus.fwStatus));
    ctrl->pack_missing = bbu_fw_status->packMissing;
    ctrl->temperature_high = bbu_fw_status->temperatureHigh;
    ctrl->voltage_low = bbu_fw_status->voltageLow;
    ctrl->replacepack = bbu_fw_status->replacePack;
    ctrl->learn_cycle_failed = bbu_fw_status->learnCycleFailed;
    ctrl->learn_cycle_timeout = bbu_fw_status->learnCycleTimeout;
    ctrl->predictive_failure = bbu_fw_status->predictiveFailure;
    ctrl->remaining_capacity_low = bbu_fw_status->remainingCapacityLow;
    ctrl->no_space = bbu_fw_status->noSpace;
    ctrl->temperature = BBUStatus.temperature;

    // BBU不在位时，读取会失败，此处不能返回失败
    return SML_SUCCESS;
}

/*
 * Description: 通过LSI storelib获取RAID卡的健康状态
 * History: 2016年3月7日    新生成函数
 *          修改传递下来的数据类型，结构体数据较小，只有需要关心的数据
*/
gint32 lsi_get_ctrl_health(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    SL_CTRL_HEALTH_T CtrlHealth;
    SML_CTRL_HEALTH_DATA_S *ctrl = NULL;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    ctrl = (SML_CTRL_HEALTH_DATA_S *)data;
    (void)memset_s(&CtrlHealth, sizeof(SL_CTRL_HEALTH_T), 0, sizeof(SL_CTRL_HEALTH_T));

    // 获取控制器健康状态
    retval = GetCtrlHealth(ctrl_id, &CtrlHealth);
    if (SML_SUCCESS == retval) {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlHealth Controller#%d NVRAM Uncorrectable Error Count = %d\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), CtrlHealth.nvramUnCorrectableErrorCount);
        ctrl->ctrl_nvram_err_count = CtrlHealth.nvramUnCorrectableErrorCount;
        ctrl->bbu_present = CtrlHealth.bbuPresent;
    } else {
        debug_log(DLOG_ERROR, "smlib: LSI:GetCtrlHealth failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}

/*
 * Description: 通过LSI storelib获取RAID卡的LD概况
 * History: 2016年3月7日    新生成函数
*/
gint32 lsi_get_ctrl_ld_list(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    guint32 idx = 0;
    MR_LD_LIST LdList;
    SML_LD_LIST_S *pLDlist = NULL;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    pLDlist = (SML_LD_LIST_S *)data;
    (void)memset_s(&LdList, sizeof(MR_LD_LIST), 0, sizeof(MR_LD_LIST));

    // 获取LDlist
    retval = GetCtrlLDList(ctrl_id, &LdList);
    if (SML_SUCCESS == retval) {
        pLDlist->ld_count = (guint16)LdList.ldCount;

        for (idx = 0; idx < pLDlist->ld_count; idx++) {
            pLDlist->target_ids[idx] = (guint16)LdList.ldList[idx].ref.targetId;
        }
    } else {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlLdList failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}

/*
 * Description: 将从RAID卡获取到的PdList数据复制到pPDlist里，之后将pPDlist返回给上层
 */
static void CopyCtrlPDList(guint32 ctrl_id, MR_PD_LIST* PdList, SML_PD_LIST_S* pPDlist)
{
    volatile guint32 idx;
    guint16 DirectAttachedPdEid = 0xffff;
    gint32 EidConverted;

    // 对物理盘Eid为0xffff(3008 IT接直通背板上的硬盘)进行转换处理，
    // 因为0xffff为无效值，直接使用会导致无法区分物理盘未识别和识别后Eid为0xffff的情况
    // 这里将其转换为其他合适的数值，SML向上层只报转换过的Eid值
    EidConverted = ConvertDirectAttachedPdEid(PdList, &DirectAttachedPdEid);

    pPDlist->pd_count = 0;
    for (idx = 0; idx < PdList->count; idx++) {
        // 只获取PD=Disk的deviceId和slot number
        if (PdList->addr[idx].scsiDevType == SPC_HARDDISK) {
            pPDlist->device_ids[pPDlist->pd_count] = PdList->addr[idx].deviceId;
            pPDlist->slot_num[pPDlist->pd_count]   = PdList->addr[idx].slotNumber;
            if (PdList->addr[idx].enclDeviceId == PD_EID_NOT_IN_ENCLOSURE) {
                pPDlist->enclosure_ids[pPDlist->pd_count] =
                    (EidConverted == TRUE) ? DirectAttachedPdEid : PdList->addr[idx].enclDeviceId;
            } else {
                pPDlist->enclosure_ids[pPDlist->pd_count]   = PdList->addr[idx].enclDeviceId;
            }
            pPDlist->pd_count++;

            if (pPDlist->pd_count >= SML_MAX_PHYSICAL_DRIVES) {
                break;
            }
        }
    }
}

/*
 * Description: 与LSI storelib适配的获取RAID卡的PD概况
 * History: 2016年3月7日    新生成函数
*/
gint32 lsi_get_ctrl_pd_list(guint32 ctrl_id, gpointer data)
{
    gint32 retval;
    guint32 dataSize;
    MR_PD_LIST *PdList = NULL;
    SML_PD_LIST_S *pPDlist = NULL;

    if (data == NULL) {
        return SML_ERR_NULL_DATA;
    }

    pPDlist = (SML_PD_LIST_S *)data;
    dataSize = (guint32)(sizeof(MR_PD_LIST) + (MAX_PHYSICAL_DEVICES - 1) * sizeof(MR_PD_ADDRESS));

    PdList = (MR_PD_LIST *)g_malloc(dataSize);
    if (PdList == NULL) {
        return SML_ERR_CANNOT_ALLOC_MEM;
    }

    (void)memset_s(PdList, dataSize, 0, dataSize);

    // 获取PDlist
    retval = GetCtrlPDList(ctrl_id, PdList, dataSize);
    if (SML_SUCCESS == retval) {
        pPDlist->pd_count = 0;
        PdList->count = (PdList->count > MAX_PHYSICAL_DEVICES) ? MAX_PHYSICAL_DEVICES : PdList->count;

        if (PdList->size != (sizeof(MR_PD_LIST) - sizeof(MR_PD_ADDRESS)) + PdList->count * sizeof(MR_PD_ADDRESS)) {
            debug_log(DLOG_DEBUG, "smlib: LSI: PdList size is invalid, CtrlId = %d, size = %u, count = %u",
                SML_CTRL_ID_VALID_BIT(ctrl_id), PdList->size, PdList->count);
            g_free(PdList);
            return SML_ERR_DATA_LEN_INVALID;
        }

        (void)CopyCtrlPDList(ctrl_id, PdList, pPDlist);

        retval =
            check_duplicate_pd_id(pPDlist->device_ids, (gsize)pPDlist->pd_count, GET_ARRAY_ITEMS(pPDlist->device_ids));
        if (retval != SML_SUCCESS) {
            debug_log(DLOG_ERROR, "smlib: LSI: check_duplicate_pd_id failed, CtrlId = %d.",
                      SML_CTRL_ID_VALID_BIT(ctrl_id));
        }
    } else {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlPDList failed, CtrlId = %d, return 0x%0x",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    g_free(PdList);
    return retval;
}

/*
 * Description: 通过LSI storelib获取RAID卡的Array列表
 * History: 2016年11月8日   ()  新生成函数
*/
gint32 lsi_get_ctrl_array_list(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    volatile guint32 idx = 0;
    MR_CONFIG_DATA *pCurrentConfig = NULL;
    SML_ARRAY_LIST_S *pArraylist = NULL;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    pArraylist = (SML_ARRAY_LIST_S *)data;
    // 获取当前已存在的RAID配置信息
    retval = ReadConfig(ctrl_id, &pCurrentConfig);
    if (SML_SUCCESS == retval) {
        pArraylist->array_count = pCurrentConfig->arrayCount;

        if (pArraylist->array_count >= SML_MAX_ARRAY) {
            pArraylist->array_count = SML_MAX_ARRAY;
        }

        for (idx = 0; idx < pArraylist->array_count; idx++) {
            pArraylist->array_refs[idx] = pCurrentConfig->array[idx].arrayRef;
        }

        g_free(pCurrentConfig);
    } else {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetCtrlArrayList failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
    }

    return retval;
}

/*
 * Description: 获取控制器BIOS启动模式
*/
gint32 lsi_get_ctrl_boot_mode(guint32 ctrl_id, gpointer data)
{
    gint32 retval = SML_SUCCESS;
    guint8 *boot_mode = NULL;

    if (NULL == data) {
        return SML_ERR_NULL_DATA;
    }

    boot_mode = (guint8 *)data;

    retval = GetCtrlBIOSBootMode(ctrl_id, boot_mode);
    if (SML_SUCCESS != retval) {
        debug_log(DLOG_DEBUG, "smlib LSI: GetCtrlBIOSBootMode failed, CtrlId = %d, return 0x%0x\n",
            SML_CTRL_ID_VALID_BIT(ctrl_id), retval);
        return retval;
    }
    return retval;
}

/*
 * Description: 通过LSI storelib对RAID控制器执行相应的操作
 * History: 2016年11月21日   () 新生成函数
*/
gint32 lsi_ctrl_operations(guint32 ctrl_id, guint8 operation, gpointer param, guint32 param_length)
{
    gint32 retval = SML_SUCCESS;
    guint8 libType = 0;

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);
    if (libType == SL_LIB_TYPE_STORELIBIR || libType == SL_LIB_TYPE_STORELIBIR_2 ||
        libType == SL_LIB_TYPE_STORELIBIR_3 || libType == SL_LIB_TYPE_STORELIBIT ||
        libType == SL_LIB_TYPE_STORELIBCUSTOM) {
        return SML_ERR_CTRL_OPERATION_NOT_SUPPORT;
    }

    switch (operation) {
        case CTRL_OPERATION_DISABLE_COPYBACK:
        case CTRL_OPERATION_ENABLE_SMART_COPYBACK:
        case CTRL_OPERATION_ENABLE_JBOD:
        case CTRL_OPERATION_SET_PERSONALITY_MODE:
        case CTRL_OPERATION_SET_BIOS_BOOT_MODE:
        case CTRL_OPERATION_SET_MAINTAIN_PDFAIL_HISTORY:
            if ((NULL == param) || (0 == param_length)) {
                return SML_ERR_NULL_DATA;
            }
            retval = SetCtrlProppertyOperations(ctrl_id, operation, param, param_length);
            break;

        case CTRL_OPERATION_RESTORE_DEFAULT:
            retval = SetCtrlRestoreDefault(ctrl_id);
            break;

        case CTRL_OPERATION_IMPORT_FOREIGN_CONFIG:
            retval = ImportCtrlForeignConfig(ctrl_id);
            break;

        case CTRL_OPERATION_CLEAR_FOREIGN_CONFIG:
            retval = ClearCtrlForeignConfig(ctrl_id);
            break;

        default:
            retval = SML_ERR_CTRL_OPERATION_NOT_SUPPORT;
            break;
    }

    return retval;
}

/*
 * Description: 获取BIOS DATA
 */
gint32 GetBIOSData(guint32 ctrl_id, MR_BIOS_DATA *biosData)
{
    guint8 libType;
    gint32 retval;
    SL_LIB_CMD_PARAM_T libCmdParam;
    SL_DCMD_INPUT_T dcmdInput;

    if (biosData == NULL) {
        return SML_ERR_NULL_DATA;
    }

    libType = LSI_STORELIB_TYPE_VALID_BIT(ctrl_id);

    (void)memset_s(&libCmdParam, SL_LIB_CMD_PARAM_S, 0, SL_LIB_CMD_PARAM_S);
    (void)memset_s(&dcmdInput, SL_DCMD_INPUT_S, 0, SL_DCMD_INPUT_S);

    dcmdInput.dataTransferLength = (guint32)sizeof(MR_BIOS_DATA);
    dcmdInput.opCode = MR_DCMD_CTRL_BIOS_DATA_GET;
    dcmdInput.flags = SL_DIR_READ;
    dcmdInput.pData = biosData;

    libCmdParam.cmdType = SL_PASSTHRU_CMD_TYPE;
    libCmdParam.cmd = SL_DCMD_PASSTHRU;
    libCmdParam.ctrlId = ctrl_id;
    libCmdParam.dataSize = (guint32)SL_DCMD_INPUT_S;
    libCmdParam.pData = &dcmdInput;

    retval = ProcessLibCommandCall(libType, &libCmdParam);
    if (retval != SL_SUCCESS) {
        debug_log(DLOG_DEBUG, "smlib: LSI:GetBIOSData -> MR_DCMD_CTRL_BIOS_DATA_GET cmd failed, return 0x%0x",
            retval);
        return retval;
    }

    // 根据boot mode校验返回的数据有效性
    if (biosData->continueOnError > MR_BOOT_MODE_MAX) {
        debug_log(DLOG_ERROR,
            "CheckVDBootable  -> MR_DCMD_CTRL_BIOS_DATA_GET cmd failed, CtrlId = 0x%08x, "
            "returned biosData.continueOnError = %d, boot mode is larger than %d",
            SML_CTRL_ID_VALID_BIT(ctrl_id), biosData->continueOnError, MR_BOOT_MODE_MAX);
        return SML_ERR_INVALID_CMD;
    }

    return retval;
}

